﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace OverStore.Runtime.ObjectRepository.ErrorTransformer
{
    /// <summary>
    /// Transforms exception of specified type which message matches specified pattern to 
    /// <see cref="OverStore.Runtime.PersistingRuntimeException"/> with predefined resulting message.
    /// </summary>
    public sealed class MatchCase
    {
        private readonly string _Pattern;
        private readonly MessageMatchType _MessageMatchType;
        private readonly Type _ExceptionType;
        private readonly string _ResultingMessage;
        private Regex _Regex;

        /// <summary>
        /// Initializes a new instance of the <see cref="MatchCase"/> class.
        /// </summary>
        /// <param name="exceptionType">Type of the exception which can be processed.</param>
        /// <param name="pattern">The pattern for compare with exception message.</param>
        /// <param name="matchType">Comparsion used for match exception message to the pattern.</param>
        /// <param name="resultingMessage">The message of rethrown exception.</param>
        public MatchCase(Type exceptionType, string pattern, MessageMatchType matchType, string resultingMessage)
        {
            if (Object.ReferenceEquals(exceptionType, null))
                throw new ArgumentNullException("exceptionType");
            if (String.IsNullOrEmpty(resultingMessage))
                throw new ArgumentNullException("resultingMessage");
            _ExceptionType = exceptionType;
            _Pattern = pattern;
            _MessageMatchType = matchType;
            _ResultingMessage = resultingMessage;
        }

        /// <summary>
        /// Gets the <see cref="Regex"/> object with pattern.
        /// </summary>
        private Regex RegEx
        {
            get
            {
                if (_Regex == null)
                    _Regex = new Regex(_Pattern);
                return _Regex;
            }
        }

        /// <summary>
        /// Processes the exception.
        /// </summary>
        public void Process(Exception ex)
        {
            Debug.Assert(ex != null, "ex != null");
            if (ex.GetType() == _ExceptionType)
            {
                var sourceMessage = ex.Message;
                bool match = false;
                switch (_MessageMatchType)
                {
                    case MessageMatchType.MessageContainsPattern:
                        match = sourceMessage.Contains(_Pattern); 
                        break;
                    case MessageMatchType.PatternEqualsMessage:
                        match = StringComparer.CurrentCulture.Equals(_Pattern, sourceMessage);
                        break;
                    case MessageMatchType.MessageMatchRegexPattern:
                        match = RegEx.IsMatch(sourceMessage);
                        break;
                    default:
                        throw new NotSupportedException();
                }
                if (match)
                    throw new PersistingRuntimeException(_ResultingMessage, ex, true);
            }
        }
    }

    /// <summary>
    /// Defines how the message of exception is checked for matching to specified pattern.
    /// </summary>
    public enum MessageMatchType
    {
        /// <summary>
        /// Message means matched pattern if message contains pattern.
        /// </summary>
        MessageContainsPattern,
        /// <summary>
        /// Message means matched pattern if message is equals to the pattern.
        /// </summary>
        PatternEqualsMessage,
        /// <summary>
        /// Message means matched pattern if message matches regular expression from the pattern.
        /// </summary>
        MessageMatchRegexPattern
    }
}
